<template>
	<view class="xin-calendar">
		<view class="calendar-control" v-if="showHeader">
			<view class="calendar-control-left">
				<XinTagBtn color="blue" content="上月" clickable @click="pre()" />
			</view>
			<view class="calendar-control-center">
				{{activeDay}}
			</view>
			<view class="calendar-control-right">
				<XinTagBtn color="blue" content="下月" clickable @click="next()" />
			</view>
		</view>
		<view class="calendar-header">
			<view class="calendar-week" v-for="(item, index) in weeks" :key="index">{{ item }}</view>
		</view>
		<view class="calendar-body">
			<swiper class="swiper" :current="current" circular adjust-height="highest" :autoplay="false"
				:indicator-dots="false" :interval="3000" :duration="500" @change="swiperChange"
				@animationfinish1="swiperChange">
				<swiper-item class="swiper-item" v-for="(calendar, calendarIndex) in calendarList" :key="calendarIndex">
					<view class="calendar-line" v-for="(line, lineIndex) in calendar.dateList" :key="lineIndex">
						<view class="calendar-day" v-for="(item, index) in line" :key="index"
							@click="clickEvent(item, index)">
							<view :class="['day-item', {
                    can: item.type === 'day',
                    pre: item.type === 'pre',
                    next: item.type === 'next',
                    today: today === item.date,
                    active: activeDay === item.date,
                  }]">
								<view class="label">{{item.day}}</view>
								<view class="desc blue"
									v-if="festival && item.lunarInfo.festival && item.type === 'day'">
									{{item.lunarInfo.festival}}</view>
								<view class="desc" v-else-if="lunar">
									{{item.lunarInfo.IDayCn === '初一' ? item.lunarInfo.IMonthCn : item.lunarInfo.IDayCn}}
								</view>
								<text class="dot" v-if="dots.indexOf(item.date) > -1"></text>
							</view>
						</view>
					</view>
				</swiper-item>
			</swiper>
		</view>
	</view>
</template>

<script>
	import moment from 'moment'
	import XinTagBtn from './xin-tag-btn.vue'
	import lunar from './lunar'
	export default {
		components: {
			XinTagBtn,
		},
		props: {
			value: {
				type: String,
				default: moment().format('YYYY-MM-DD'),
			},
			background: {
				type: String,
				default: '#ffffff'
			},
			showHeader: {
				type: Boolean,
				default: false
			},
			dots: {
				type: Array,
				default: () => [],
			},
			lunar: {
				type: Boolean,
				default: true,
			},
			festival: {
				type: Boolean,
				default: true,
			},
		},
		data() {
			return {
				weeks: ['日', '一', '二', '三', '四', '五', '六', ],
				dateList: [],
				today: moment().format('YYYY-MM-DD'),
				activeDay: moment().format('YYYY-MM-DD'),
				current: 1,
				calendarList: [{
						date: moment().add(-1, 'months').startOf('month').format('YYYY-MM'),
						dateList: [],
					},
					{
						date: moment().startOf('month').format('YYYY-MM'),
						dateList: [],
					},
					{
						date: moment().add(1, 'months').startOf('month').format('YYYY-MM'),
						dateList: [],
					},
				],
			}
		},
		computed: {},
		filters: {},
		watch: {
			value(n, o) {
				this.activeDay = n
			},
			activeDay(n, o) {
				this.$emit('input', n)
				this.$emit('change', n)
				this.init()
			},
		},
		mounted() {
			if (this.value) this.activeDay = this.value
			this.init()
		},
		methods: {
			init() {
				this.calendarList.forEach((item, index) => {
					item.dateList = this.createMonthDays(item.date)
				})
			},
			pre() {
				this.current = this.current - 1 < 0 ? 2 : this.current - 1
			},
			next() {
				this.current = this.current + 1 > 2 ? 0 : this.current + 1
			},
			clickEvent(item, index) {
				if (item.type !== 'day') return
				this.activeDay = item.date
			},
			createMonthDays(date) {
				let list = [];
				let monthInfo = this.getMomentInfo(date + '-01')
				for (let i = 0; i < monthInfo.daysInMonth; i++) {
					let dd = moment(monthInfo.firstDayInMonth).add(i, 'days')
					let dayInfo = this.getMomentInfo(dd)
					let day = {
						type: 'day',
						...dayInfo,
					};
					list.push(day);
				}
				let pre = [];
				for (let i = 0; i < monthInfo.weekday; i++) {
					let dd = moment(monthInfo.firstDayInMonth).add(-(monthInfo.weekday - i), 'days')
					let dayInfo = this.getMomentInfo(dd)
					pre.push({
						type: 'pre',
						...dayInfo,
					});
				}
				let next = [];
				let length = 42 - monthInfo.weekday - monthInfo.daysInMonth;
				for (let i = 0; i < length; i++) {
					let dd = moment(monthInfo.lastDayInMonth).add(i + 1, 'days')
					let dayInfo = this.getMomentInfo(dd)
					next.push({
						type: 'next',
						...dayInfo,
					});
				}
				list = [...pre, ...list, ...next];
				let result = [];
				for (let i = 0; i < list.length; i += 7) {
					result.push(list.slice(i, i + 7));
				}
				return result;
			},
			swiperChange(e) {
				let current = e.detail.current
				let preIndex = current - 1 > -1 ? current - 1 : 2
				let nextIndex = current + 1 > 2 ? 0 : current + 1
				let preMoment = moment(this.calendarList[current].date + '-01').add(-1, 'months')
				if (preMoment.format('YYYY-MM') != moment().format('YYYY-MM')) {
					preMoment = preMoment.startOf('month')
				} else {
					preMoment = moment()
				}
				this.calendarList[preIndex].date = preMoment.format('YYYY-MM')
				let nextMoment = moment(this.calendarList[current].date + '-01').add(1, 'months')
				if (nextMoment.format('YYYY-MM') != moment().format('YYYY-MM')) {
					nextMoment = nextMoment.startOf('month')
				} else {
					nextMoment = moment()
				}
				this.calendarList[nextIndex].date = nextMoment.format('YYYY-MM')
				if (moment().format('YYYY-MM') === this.calendarList[current].date) {
					this.activeDay = moment().format('YYYY-MM-DD')
				} else {
					this.activeDay = this.calendarList[current].date + '-01'
				}
				this.$nextTick(() => {
					this.$emit('monthChange', this.activeDay)
				})
			},
			getMomentInfo(date) {
				let m = moment(date)
				return {
					moment: m,
					firstDayInMonth: moment(m).startOf('month').format('YYYY-MM-DD'),
					lastDayInMonth: moment(m).startOf('month').add(m.daysInMonth() - 1, 'days').format('YYYY-MM-DD'),
					date: m.format('YYYY-MM-DD'),
					year: m.format('YYYY'),
					month: m.format('MM'),
					day: m.format('DD'),
					weekday: m.weekday(),
					daysInMonth: m.daysInMonth(),
					stamp: Number(m.format('x')),
					lunarInfo: lunar.solar2lunar(Number(m.format('YYYY')), Number(m.format('MM')), Number(m.format('DD')))
				}
			},
		}
	}
</script>

<style>
	.xin-calendar .calendar-control {
		display: flex;
		margin-bottom: 18rpx;
	}

	.xin-calendar .calendar-control .calendar-control-left {
		flex: 1;
	}

	.xin-calendar .calendar-control .calendar-control-center {
		display: flex;
		justify-content: center;
		align-items: center;
	}

	.xin-calendar .calendar-control .calendar-control-right {
		flex: 1;
		text-align: right;
	}

	.xin-calendar .calendar-header {
		display: flex;
	}

	.xin-calendar .calendar-header .calendar-week {
		flex: 1;
		text-align: center;
		line-height: 60rpx;
	}

	.xin-calendar .calendar-body .swiper {
		height: 640rpx;
		min-height: 640rpx;
	}

	.xin-calendar .calendar-body .swiper .swiper-item {
		height: 640rpx;
		min-height: 640rpx;
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line {
		display: flex;
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day {
		flex: 1;
		display: flex;
		justify-content: center;
		align-items: center;
		padding: 9rpx 0;
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item {
		width: 90rpx;
		height: 90rpx;
		background: #f6f7ff;
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		border-radius: 100%;
		transition: all 0.15s;
		position: relative;
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item .label {
		font-size: 32rpx;
		line-height: 32rpx;
		margin: 4rpx 0 8rpx 0;
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item .desc {
		font-size: 16rpx;
		opacity: 0.5;
		line-height: 16rpx;
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item .desc.blue {
		color: #0095ff;
		opacity: 0.7;
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.can.today {
		background: #ffffff;
		color: #0095ff;
		font-weight: bold;
		box-shadow: 5rpx 5rpx 15rpx rgba(34, 34, 34, 0.08);
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.can.today .dot {
		display: none;
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.can.active {
		background: #0095ff;
		color: #ffffff;
		font-weight: bold;
		box-shadow: 5rpx 5rpx 15rpx rgba(0, 149, 255, 0.5);
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.can.active .dot {
		display: none;
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.can.active .desc.blue {
		color: #ffffff;
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.can .dot {
		position: absolute;
		bottom: 0;
		left: 50%;
		transform: translateX(-50%);
		width: 8rpx;
		height: 8rpx;
		border-radius: 100%;
		background: #0095ff;
	}

	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.pre,
	.xin-calendar .calendar-body .swiper .swiper-item .calendar-line .calendar-day .day-item.next {
		opacity: 0.15;
	}
</style>

<style lang="less">
	// 源码修改可以在这里
	// 尺寸
	@font-size: 26rpx;
	@space-width: 18rpx;
	@radius-width: 18rpx;
	// 颜色
	@color-gray: #222222;
	@color-blue: #0095ff;
	@color-green: #15bf81;
	@color-yellow: #f7ab42;
	@color-red: #ff6666;
	@color-background: #f6f7ff;

	// 方法
	.shadow (@color: @color-gray, @x: 5rpx, @y: 5rpx, @r: 15rpx, @o: 3) {
		box-shadow: @x @y @r fade(@color, @o);
	}

	.xin-calendar {
		.calendar-control {
			display: flex;
			margin-bottom: @space-width;

			.calendar-control-left {
				flex: 1;
			}

			.calendar-control-center {
				display: flex;
				justify-content: center;
				align-items: center;
			}

			.calendar-control-right {
				flex: 1;
				text-align: right;
			}
		}

		.calendar-header {
			display: flex;

			.calendar-week {
				flex: 1;
				text-align: center;
				line-height: 60rpx;
			}
		}

		.calendar-body {
			.swiper {
				height: 640rpx;
				min-height: 640rpx;

				.swiper-item {
					height: 640rpx;
					min-height: 640rpx;

					.calendar-line {
						display: flex;

						.calendar-day {
							flex: 1;
							display: flex;
							justify-content: center;
							align-items: center;
							padding: @space-width / 2 0;

							.day-item {
								width: 90rpx;
								height: 90rpx;
								background: @color-background;
								display: flex;
								flex-direction: column;
								justify-content: center;
								align-items: center;
								border-radius: 100%;
								transition: all 0.15s;
								position: relative;

								.label {
									font-size: @font-size + 6rpx;
									line-height: @font-size + 6rpx;
									margin: 4rpx 0 8rpx 0;
								}

								.desc {
									font-size: @font-size - 10rpx;
									opacity: 0.5;
									line-height: @font-size - 10rpx;

									&.blue {
										color: @color-blue;
										opacity: 0.7;
									}
								}

								&.can {
									&.today {
										background: #ffffff;
										color: @color-blue;
										font-weight: bold;
										.shadow(@color: @color-gray, @o: 8);

										.dot {
											display: none;
										}
									}

									&.active {
										background: @color-blue;
										color: #ffffff;
										font-weight: bold;
										.shadow(@color: @color-blue, @o: 50);

										.dot {
											display: none;
										}

										.desc {
											&.blue {
												color: #ffffff;
											}
										}
									}

									.dot {
										position: absolute;
										bottom: 0;
										left: 50%;
										transform: translateX(-50%);
										width: 8rpx;
										height: 8rpx;
										border-radius: 100%;
										background: @color-blue;
									}
								}

								&.pre,
								&.next {
									opacity: 0.15;
								}
							}
						}
					}
				}
			}
		}
	}
</style>